package com.lsh.security.config;

import com.lsh.security.handler.MyAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author ：LiuShihao
 * @date ：Created in 2021/8/18 11:49 上午
 * @desc ：
 */
@Configuration
// 开启SpringSecurity注解使用原本在配置类中配置的路径和角色对应关系由注解取代
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 定义用户信息服务（查询用户信息） 如果自定义UserDetailService实现了UserDetailService接口则不需要了
     * @return
     */
//    @Override
//    @Bean
//    public UserDetailsService userDetailsService(){
//        //不查询数据库 使用内存用户详细信息管理器 在内存中构造出用户信息
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1","p3").build());
//        manager.createUser(User.withUsername("lisi").password("456").authorities("p2","p4").build());
//        return manager;
//    }

    /**
     * 密码编码器  NoOpPasswordEncoder采用字符串匹配方法，不对密码进行加密处理
     * 实际项目中推荐 BCryptPasswordEncoder 、 Pbkdf2PasswordEncoder、SCryptPasswordEncoder
     * @return
     */
//    @Bean
//    public PasswordEncoder passwordEncoder(){
//        return NoOpPasswordEncoder.getInstance();
//    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 安全拦截机制  最重要
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                //开启注解后，可以直接使用注解进行认证
                .antMatchers("/anno").permitAll()//访问/anno 不需要认证 匿名访问
//                .antMatchers("/r/r3").hasRole("USER") //访问/r/r3需要USER的角色
//                .antMatchers("/r/r4").hasRole("ADMIN")
//                .antMatchers("/r/r1").hasAuthority("p1")//访问/r/r1需要p1的权限
//                .antMatchers("/r/r2").hasAuthority("p2")
//                .anyRequest().permitAll()//除了以上需要认证的请求，其他请求都可以访问
                .anyRequest().authenticated()//其他请求需要认证
                .and()
                //允许表单登录
                .formLogin()
                //登陆页面 跳转自定义的登录页面，如果不设置则如果登录失败 跳转默认Security的登陆页面
//                .loginPage("/login-view")
                //自定义登录页面 login.html 的登录form 提交的 地址
//                .loginProcessingUrl("/login")
                //自定义登录成功的页面地址
                .successForwardUrl("/login-success")
                //自定义登出
                .and()
                .logout()
                //登出URL
                .logoutUrl("/logout")
                //登出成功后的跳转页面   一般是登录页面
                .logoutSuccessUrl("/login")
                .and()
                .exceptionHandling()
                //设置无权限的处理类
                .accessDeniedHandler(myAccessDeniedHandler);


    }
    @Override
    public void configure(WebSecurity web) {
        // 设置拦截忽略文件夹，可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

}
